import bpmn.BPMNHandler;
import bpmn.BPMNParser;
import bpmn.structure.*;
import common.FSUtils;
import org.xml.sax.SAXException;
import ta.TAGenerator;
import ta.structure.TADefinition;

import java.io.File;
import java.util.HashMap;
import java.util.List;

public class BPMNLoader
{
	private final HashMap<String, BPMNDefinition> bpmnContainer;
	private final boolean isDebug;
	private String inputPath;
	private String outputPath;

	public BPMNLoader(boolean debug, String input_dir, String output_dir)
	{
		bpmnContainer = new HashMap<>();
		isDebug = debug;
		inputPath = input_dir;
		outputPath = output_dir;
	}

	public HashMap<String, BPMNDefinition> getBpmnContainer()
	{
		return bpmnContainer;
	}

	@Deprecated
	public BPMNDefinition loadBPMN(String file_name_no_ext)
	{
		BPMNParser parser = new BPMNParser(new BPMNHandler());
		parser.parse(String.format("%s/%s.bpmn", inputPath, file_name_no_ext));
		BPMNDefinition bpmn = parser.getXmlBPMN();
		TestPrintBPMN(bpmn);
		bpmnContainer.put(file_name_no_ext, bpmn);
		return bpmn;
	}

	public void loadBPMNs()
	{
		BPMNParser parser = new BPMNParser(new BPMNHandler());
		List<File> files = FSUtils.getFileInDirWithExt(inputPath, "bpmn");
		for (var file : files)
		{
			parser.parse(file);
			BPMNDefinition bpmn = parser.getXmlBPMN();
			TestPrintBPMN(bpmn);
			bpmnContainer.put(file.getName(), bpmn);
		}
	}


	private void TestPrintTA(TADefinition ta)
	{
		if (!isDebug)
			return;
		System.out.printf("<ta name>: %s\n", ta.getName());
		System.out.println("<ta vars>:");
		for (var p : ta.getGlobals().getDefs().entrySet())
		{
			System.out.printf("\t[key, value]: %s ", p.getKey());
			for (var v : p.getValue())
			{
				System.out.printf("%s ", v);
			}
			System.out.println();
		}
		// template
		System.out.println("<ta templates>:");
		for (var p : ta.getTemplates().values())
		{
			System.out.printf("\t[template name]: %s\n", p.getName());
			// locations
			System.out.println("\t[locations]:");
			for (var n : p.getLocations())
			{
				System.out.printf("\t\t{loc id-name}: %s - %s - (%d,%d)\n", n.getId(), n.getName(), n.x, n.y);
			}

			// transitions
			System.out.println("\t[transitions]:");
			for (var t : p.getTransitions())
			{
				System.out.printf("\t\t{trans id-name}: %s - %s - (%d,%d)\n", t.getId(), t.getName(), t.x, t.y);
				System.out.printf("\t\t\t- link -: %s => %s\n", t.getSourceRef(), t.getTargetRef());
				System.out.printf("\t\t\t- select -: %s\n", t.getSelect());
				System.out.printf("\t\t\t- guard -: %s\n", t.getGuard());
				System.out.printf("\t\t\t- sync -: %s\n", t.getSync());
				System.out.printf("\t\t\t- update -: %s\n", t.getUpdate());
			}
		}
	}

	private void TestPrintBPMN(BPMNDefinition bpmn)
	{
		if (!isDebug)
			return;
		System.out.println("===========================");
		System.out.printf("<bpmn id>: %s\n", bpmn.id);
		if (bpmn.getCollaboration() != null)
		{
			System.out.printf("<coll id>: %s\n", bpmn.getCollaboration().id);
			System.out.println("participants:");
			// collaboration
			for (var p : bpmn.getCollaboration().getParticipants())
			{
				System.out.printf("\t[part id]: %s\n", p.id);
				System.out.printf("\t[part re]: %s-%s\n", p.getProcessRef(), bpmn.elemMap.get(p.getProcessRef()).type);
			}
		}

		// process
		for (var p : bpmn.getProcessList())
		{
			System.out.printf("<proc id>: %s\n", p.id);
			System.out.printf("<proc ex>: %s\n", p.isExecutable());

			// laneSet
			if (p.getLaneSet() != null)
			{
				System.out.printf("<lSet id>: %s\n", p.getLaneSet().id);
				for (var l : p.getLaneSet().getLanes())
				{
					// lane
					System.out.printf("\t[lane id]: %s\n", l.id);
					System.out.printf("\t[lane na]: %s\n", l.getName());
					for (var r : l.getRefs())
						// flowNodeRef
						System.out.printf("\t\t-node re-: %s-%s\n", r, bpmn.elemMap.get(r).type);
				}
			}

			for (var e : p.getElements())
			{
				BPMNElemType type = e.type;
				switch (type)
				{
					// task
					case Task:
					{
						assert e instanceof Task;
						Task t = (Task) e;
						System.out.printf("<task id>: %s\n", t.id);
						System.out.printf("<task na>: %s\n", t.getName());
						// incoming
						System.out.println("incomingRefs:");
						for (var i : t.getIncomingRefs())
							System.out.printf("\t[flow re]: %s-%s\n", i, bpmn.elemMap.get(i).type);
						// outgoing
						System.out.println("outgoingRefs:");
						for (var o : t.getOutgoingRefs())
							System.out.printf("\t[flow re]: %s-%s\n", o, bpmn.elemMap.get(o).type);
						break;
					}
					case SequenceFlow:
					{
						assert e instanceof SequenceFlow;
						SequenceFlow s = (SequenceFlow) e;
						System.out.printf("<sequ id>: %s\n", s.id);
						System.out.printf("<sequ na>: %s\n", s.getName());
						System.out.printf("<sequ sc>: %s-%s\n", s.getSourceRef(), bpmn.elemMap
								.get(s.getSourceRef()).type);
						System.out.printf("<sequ tg>: %s-%s\n", s.getTargetRef(), bpmn.elemMap
								.get(s.getTargetRef()).type);
						break;
					}
					case StartEvent:
					{
						assert e instanceof StartEvent;
						StartEvent se = (StartEvent) e;
						System.out.printf("<sEvt id>: %s\n", se.id);
						System.out.printf("<sEvt na>: %s\n", se.getName());
						// outgoing
						System.out.println("outgoingRefs:");
						for (var o : se.getOutgoingRefs())
							System.out.printf("\t[flow re]: %s-%s\n", o, bpmn.elemMap.get(o).type);
						break;
					}
					case EndEvent:
					{
						assert e instanceof EndEvent;
						EndEvent ee = (EndEvent) e;
						System.out.printf("<eEvt id>: %s\n", ee.id);
						System.out.printf("<eEvt na>: %s\n", ee.getName());
						// incoming
						System.out.println("incomingRefs:");
						for (var o : ee.getIncomingRefs())
							System.out.printf("\t[flow re]: %s-%s\n", o, bpmn.elemMap.get(o).type);
						break;
					}
					case ExclusiveGateway:
					{
						assert e instanceof ExclusiveGateway;
						ExclusiveGateway eg = (ExclusiveGateway) e;
						System.out.printf("<eGty id>: %s\n", eg.id);
						System.out.printf("<eGty na>: %s\n", eg.getName());
						// incoming
						System.out.println("incomingRefs:");
						for (var i : eg.getIncomingRefs())
							System.out.printf("\t[flow re]: %s-%s\n", i, bpmn.elemMap.get(i).type);
						// outgoing
						System.out.println("outgoingRefs:");
						for (var o : eg.getOutgoingRefs())
							System.out.printf("\t[flow re]: %s-%s\n", o, bpmn.elemMap.get(o).type);
						break;
					}
					case ParallelGateway:
					{
						assert e instanceof ParallelGateway;
						ParallelGateway pg = (ParallelGateway) e;
						System.out.printf("<pGty id>: %s\n", pg.id);
						System.out.printf("<pGty na>: %s\n", pg.getName());
						// incoming
						System.out.println("incomingRefs:");
						for (var i : pg.getIncomingRefs())
							System.out.printf("\t[flow re]: %s-%s\n", i, bpmn.elemMap.get(i).type);
						// outgoing
						System.out.println("outgoingRefs:");
						for (var o : pg.getOutgoingRefs())
							System.out.printf("\t[flow re]: %s-%s\n", o, bpmn.elemMap.get(o).type);
						break;
					}
				}
			}
		}
		System.out.println("===========================");
		//
	}
}
